#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <linux/netlink.h>

#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>

#include "nl80211.h"

#define ETH_ALEN 6
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0]))
#define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y))

struct nl80211_state
{
    struct nl_sock *nl_sock;
    int nl80211_id;
};

struct nl80211_state nlstate;

char handler_script[256] = {0};
int handler_script_set = 0;

int get_interface_info(struct nl80211_state *state, int devidx);

static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
                         void *arg)
{
    int *ret = arg;
    *ret = err->error;
    return NL_STOP;
}

static int finish_handler(struct nl_msg *msg, void *arg)
{
    int *ret = arg;
    *ret = 0;
    return NL_SKIP;
}

static int ack_handler(struct nl_msg *msg, void *arg)
{
    int *ret = arg;
    *ret = 0;
    return NL_STOP;
}

struct handler_args
{
    const char *group;
    int id;
};

static int family_handler(struct nl_msg *msg, void *arg)
{
    struct handler_args *grp = arg;
    struct nlattr *tb[CTRL_ATTR_MAX + 1];
    struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    struct nlattr *mcgrp;
    int rem_mcgrp;

    nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), NULL);

    if (!tb[CTRL_ATTR_MCAST_GROUPS])
        return NL_SKIP;

    nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp)
    {
        struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];

        nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
                  nla_data(mcgrp), nla_len(mcgrp), NULL);

        if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
            !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
            continue;
        if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
                    grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
            continue;
        grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
        break;
    }

    return NL_SKIP;
}

int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
{
    struct nl_msg *msg;
    struct nl_cb *cb;
    int ret, ctrlid;
    struct handler_args grp = {
        .group = group,
        .id = -ENOENT,
    };

    msg = nlmsg_alloc();
    if (!msg)
        return -ENOMEM;

    cb = nl_cb_alloc(NL_CB_DEFAULT);
    if (!cb)
    {
        ret = -ENOMEM;
        goto out_fail_cb;
    }

    ctrlid = genl_ctrl_resolve(sock, "nlctrl");

    genlmsg_put(msg, 0, 0, ctrlid, 0,
                0, CTRL_CMD_GETFAMILY, 0);

    ret = -ENOBUFS;
    NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);

    ret = nl_send_auto_complete(sock, msg);
    if (ret < 0)
        goto out;

    ret = 1;

    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp);

    while (ret > 0)
        nl_recvmsgs(sock, cb);

    if (ret == 0)
        ret = grp.id;
nla_put_failure:
out:
    nl_cb_put(cb);
out_fail_cb:
    nlmsg_free(msg);
    return ret;
}

void mac_addr_n2a(char *mac_addr, const unsigned char *arg)
{
    int i, l;

    l = 0;
    for (i = 0; i < ETH_ALEN; i++)
    {
        if (i == 0)
        {
            sprintf(mac_addr + l, "%02x", arg[i]);
            l += 2;
        }
        else
        {
            sprintf(mac_addr + l, ":%02x", arg[i]);
            l += 3;
        }
    }
}

//====================== //
static const char *status_table[] = {
    [0] = "Successful",
    [1] = "Unspecified failure",
    [10] = "Cannot support all requested capabilities in the capability information field",
    [11] = "Reassociation denied due to inability to confirm that association exists",
    [12] = "Association denied due to reason outside the scope of this standard",
    [13] = "Responding station does not support the specified authentication algorithm",
    [14] = "Received an authentication frame with authentication transaction sequence number out of expected sequence",
    [15] = "Authentication rejected because of challenge failure",
    [16] = "Authentication rejected due to timeout waiting for next frame in sequence",
    [17] = "Association denied because AP is unable to handle additional associated STA",
    [18] = "Association denied due to requesting station not supporting all of the data rates in the BSSBasicRateSet parameter",
    [19] = "Association denied due to requesting station not supporting the short preamble option",
    [20] = "Association denied due to requesting station not supporting the PBCC modulation option",
    [21] = "Association denied due to requesting station not supporting the channel agility option",
    [22] = "Association request rejected because Spectrum Management capability is required",
    [23] = "Association request rejected because the information in the Power Capability element is unacceptable",
    [24] = "Association request rejected because the information in the Supported Channels element is unacceptable",
    [25] = "Association request rejected due to requesting station not supporting the short slot time option",
    [26] = "Association request rejected due to requesting station not supporting the ER-PBCC modulation option",
    [27] = "Association denied due to requesting STA not supporting HT features",
    [28] = "R0KH Unreachable",
    [29] = "Association denied because the requesting STA does not support the PCO transition required by the AP",
    [30] = "Association request rejected temporarily; try again later",
    [31] = "Robust Management frame policy violation",
    [32] = "Unspecified, QoS related failure",
    [33] = "Association denied due to QAP having insufficient bandwidth to handle another QSTA",
    [34] = "Association denied due to poor channel conditions",
    [35] = "Association (with QBSS) denied due to requesting station not supporting the QoS facility",
    [37] = "The request has been declined",
    [38] = "The request has not been successful as one or more parameters have invalid values",
    [39] = "The TS has not been created because the request cannot be honored. However, a suggested Tspec is provided so that the initiating QSTA may attempt to send another TS with the suggested changes to the TSpec",
    [40] = "Invalid Information Element",
    [41] = "Group Cipher is not valid",
    [42] = "Pairwise Cipher is not valid",
    [43] = "AKMP is not valid",
    [44] = "Unsupported RSN IE version",
    [45] = "Invalid RSN IE Capabilities",
    [46] = "Cipher suite is rejected per security policy",
    [47] = "The TS has not been created. However, the HC may be capable of creating a TS, in response to a request, after the time indicated in the TS Delay element",
    [48] = "Direct link is not allowed in the BSS by policy",
    [49] = "Destination STA is not present within this QBSS",
    [50] = "The destination STA is not a QSTA",
    [51] = "Association denied because Listen Interval is too large",
    [52] = "Invalid Fast BSS Transition Action Frame Count",
    [53] = "Invalid PMKID",
    [54] = "Invalid MDIE",
    [55] = "Invalid FTIE",
};

const char *get_status_str(uint16_t status)
{
    if (status < ARRAY_SIZE(status_table) && status_table[status])
        return status_table[status];
    return "<unknown>";
}

//==================== //
static const char *reason_table[] = {
    [1] = "Unspecified",
    [2] = "Previous authentication no longer valid",
    [3] = "Deauthenticated because sending station is leaving (or has left) the IBSS or ESS",
    [4] = "Disassociated due to inactivity",
    [5] = "Disassociated because AP is unable to handle all currently associated STA",
    [6] = "Class 2 frame received from non-authenticated station",
    [7] = "Class 3 frame received from non-authenticated station",
    [8] = "Disassociated because sending station is leaving (or has left) the BSS",
    [9] = "Station requesting (re)association is not authenticated with responding station",
    [10] = "Disassociated because the information in the Power Capability element is unacceptable",
    [11] = "Disassociated because the information in the Supported Channels element is unacceptable",
    [13] = "Invalid information element",
    [14] = "MIC failure",
    [15] = "4-way handshake timeout",
    [16] = "Group key update timeout",
    [17] = "Information element in 4-way handshake different from (Re-)associate request/Probe response/Beacon",
    [18] = "Multicast cipher is not valid",
    [19] = "Unicast cipher is not valid",
    [20] = "AKMP is not valid",
    [21] = "Unsupported RSNE version",
    [22] = "Invalid RSNE capabilities",
    [23] = "IEEE 802.1X authentication failed",
    [24] = "Cipher Suite rejected per security policy",
    [31] = "TS deleted because QoS AP lacks sufficient bandwidth for this QoS STA due to a change in BSS service characteristics or operational mode",
    [32] = "Disassociated for unspecified QoS-related reason",
    [33] = "Disassociated because QAP lacks sufficient bandwidth for this STA",
    [34] = "Disassociated because of excessive frame losses and/or poor channel conditions",
    [35] = "Disassociated because QSTA is transmitting outside the limits of its polled TXOPs",
    [36] = "Requested from peer QSTA as the QSTA is leaving the QBSS (or resetting)",
    [37] = "Requested from peer QSTA as it does not want to use Traffic Stream",
    [38] = "Requested from peer QSTA as the QSTA received frames indicated Traffic Stream for which it has not set up",
    [39] = "Requested from peer QSTA due to time out",
    [40] = "Requested from peer QSTA as the QSTA is leaving the QBSS (or resetting)",
    [41] = "Requested from peer QSTA as it does not want to receive frames directly from the QSTA",
    [42] = "Requested from peer QSTA as the QSTA received DLP frames for which it has not set up",
    [43] = "Requested from peer QSTA as it does not want to use Block Ack",
    [44] = "Requested from peer QSTA as the QSTA received frames indicated Block Acknowledgement policy for which it has not set up",
    [45] = "Peer QSTA does not support the requested cipher suite",
};

const char *get_reason_str(uint16_t reason)
{
    if (reason < ARRAY_SIZE(reason_table) && reason_table[reason])
        return reason_table[reason];
    return "<unknown>";
}

int ieee80211_frequency_to_channel(int freq)
{
    /* see 802.11-2007 17.3.8.3.2 and Annex J */
    if (freq == 2484)
        return 14;
    /* see 802.11ax D6.1 27.3.23.2 and Annex E */
    else if (freq == 5935)
        return 2;
    else if (freq < 2484)
        return (freq - 2407) / 5;
    else if (freq >= 4910 && freq <= 4980)
        return (freq - 4000) / 5;
    else if (freq < 5950)
        return (freq - 5000) / 5;
    else if (freq <= 45000) /* DMG band lower limit */
        /* see 802.11ax D6.1 27.3.23.2 */
        return (freq - 5950) / 5;
    else if (freq >= 58320 && freq <= 70200)
        return (freq - 56160) / 2160;
    else
        return 0;
}
char *channel_width_name(enum nl80211_chan_width width)
{
    switch (width)
    {
    case NL80211_CHAN_WIDTH_20_NOHT:
        return "20 MHz (no HT)";
    case NL80211_CHAN_WIDTH_20:
        return "20 MHz";
    case NL80211_CHAN_WIDTH_40:
        return "40 MHz";
    case NL80211_CHAN_WIDTH_80:
        return "80 MHz";
    case NL80211_CHAN_WIDTH_80P80:
        return "80+80 MHz";
    case NL80211_CHAN_WIDTH_160:
        return "160 MHz";
    case NL80211_CHAN_WIDTH_5:
        return "5 MHz";
    case NL80211_CHAN_WIDTH_10:
        return "10 MHz";
    case NL80211_CHAN_WIDTH_320:
        return "320 MHz";
    default:
        return "unknown";
    }
}
static char *channel_type_name(enum nl80211_channel_type channel_type)
{
    switch (channel_type)
    {
    case NL80211_CHAN_NO_HT:
        return "NO HT";
    case NL80211_CHAN_HT20:
        return "HT20";
    case NL80211_CHAN_HT40MINUS:
        return "HT40-";
    case NL80211_CHAN_HT40PLUS:
        return "HT40+";
    default:
        return "unknown";
    }
}

//=============================logic ===================================//

static int nl80211_init(struct nl80211_state *state)
{
    int err;

    state->nl_sock = nl_socket_alloc();
    if (!state->nl_sock)
    {
        fprintf(stderr, "Failed to allocate netlink socket.\n");
        return -ENOMEM;
    }

    if (genl_connect(state->nl_sock))
    {
        fprintf(stderr, "Failed to connect to generic netlink.\n");
        err = -ENOLINK;
        goto out_handle_destroy;
    }

    nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);

    /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
    err = 1;
    setsockopt(nl_socket_get_fd(state->nl_sock), SOL_NETLINK,
               NETLINK_EXT_ACK, &err, sizeof(err));

    state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
    if (state->nl80211_id < 0)
    {
        fprintf(stderr, "nl80211 not found.\n");
        err = -ENOENT;
        goto out_handle_destroy;
    }

    return 0;

out_handle_destroy:
    nl_socket_free(state->nl_sock);
    return err;
}

static void nl80211_cleanup(struct nl80211_state *state)
{
    nl_socket_free(state->nl_sock);
}

int __prepare_listen_events(struct nl80211_state *state)
{
    int mcid, ret;

    /* Configuration multicast group */
    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
    if (mcid < 0)
        return mcid;

    ret = nl_socket_add_membership(state->nl_sock, mcid);
    if (ret)
        return ret;

    /* Scan multicast group */
    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
    if (mcid >= 0)
    {
        ret = nl_socket_add_membership(state->nl_sock, mcid);
        if (ret)
            return ret;
    }

    /* Regulatory multicast group */
    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
    if (mcid >= 0)
    {
        ret = nl_socket_add_membership(state->nl_sock, mcid);
        if (ret)
            return ret;
    }

    /* MLME multicast group */
    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
    if (mcid >= 0)
    {
        ret = nl_socket_add_membership(state->nl_sock, mcid);
        if (ret)
            return ret;
    }

    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "vendor");
    if (mcid >= 0)
    {
        ret = nl_socket_add_membership(state->nl_sock, mcid);
        if (ret)
            return ret;
    }

    mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "nan");
    if (mcid >= 0)
    {
        ret = nl_socket_add_membership(state->nl_sock, mcid);
        if (ret)
            return ret;
    }

    return 0;
}

int iw_debug = 0;
int loop = 0;

static int no_seq_check(struct nl_msg *msg, void *arg)
{
    return NL_OK;
}

static int (*registered_handler)(struct nl_msg *, void *);
static void *registered_handler_data;

void register_handler(int (*handler)(struct nl_msg *, void *), void *data)
{
    registered_handler = handler;
    registered_handler_data = data;
}

int valid_handler(struct nl_msg *msg, void *arg)
{
    if (registered_handler)
        return registered_handler(msg, registered_handler_data);

    return NL_OK;
}

static int print_event(struct nl_msg *msg, void *arg)
{
    char exec_str[512] = {0};
    struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst;
    char ifname[100];
    char macbuf[6 * 3];
    uint16_t status;
    uint32_t ifidx = 0;

    nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), NULL);

    nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), NULL);

    if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY])
    {
        ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
        /* if_indextoname may fails on delete interface/wiphy event */
        if (if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname))
            printf("%s (idx #%d) (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_IFINDEX]), nla_get_u32(tb[NL80211_ATTR_WIPHY]));
        else
            printf("(idx #%d) phy #%d: ", nla_get_u32(tb[NL80211_ATTR_IFINDEX]), nla_get_u32(tb[NL80211_ATTR_WIPHY]));
    }
    else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY])
    {
        printf("wdev 0x%llx (phy #%d): ",
               (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]),
               nla_get_u32(tb[NL80211_ATTR_WIPHY]));
    }
    else if (tb[NL80211_ATTR_IFINDEX])
    {
        if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
        printf("%s: ", ifname);
    }
    else if (tb[NL80211_ATTR_WDEV])
    {
        printf("wdev 0x%llx: ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]));
    }
    else if (tb[NL80211_ATTR_WIPHY])
    {
        printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
    }

    printf(" (cmd %d) ", gnlh->cmd);
    int connected = 0;
    int disconnected = 0;

    switch (gnlh->cmd)
    {
    case NL80211_CMD_CONNECT:
        status = 0;
        if (tb[NL80211_ATTR_TIMED_OUT])
            printf("timed out");
        else if (!tb[NL80211_ATTR_STATUS_CODE])
            printf("unknown connect status");
        else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0)
        {
            connected = 1;
            printf("connected");
        }

        else
        {
            status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]);
            printf("failed to connect");
        }
        if (tb[NL80211_ATTR_MAC])
        {
            mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
            printf(" to %s", macbuf);
        }
        if (status)
            printf(", status: %d: %s", status, get_status_str(status));
        printf("\n");
        break;
    case NL80211_CMD_DISCONNECT:
        printf("disconnected");
        disconnected = 1;
        if (tb[NL80211_ATTR_DISCONNECTED_BY_AP])
            printf(" (by AP)");
        else
            printf(" (local request)");
        if (tb[NL80211_ATTR_REASON_CODE])
            printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]),
                   get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE])));
        printf("\n");
        break;
    default:
        printf("\n");
    }
    if (connected && ifidx)
    {
        get_interface_info(&nlstate, ifidx);
    }
    else if (disconnected && ifidx)
    {
        if (!handler_script_set)
        {
            return 0;
        }
        snprintf(exec_str, sizeof(exec_str), "%s %s %s phy%d &", handler_script, "disconnected", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
        system(exec_str);
    }
}

int __do_listen_events(struct nl80211_state *state)
{
    struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);

    if (!cb)
    {
        fprintf(stderr, "failed to allocate netlink callbacks\n");
        return -ENOMEM;
    }

    /* no sequence checking for multicast messages */
    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL);

    register_handler(print_event, NULL);

    while (!loop)
        nl_recvmsgs(state->nl_sock, cb);

    nl_cb_put(cb);
}

//==================================== get interface info =========================//
int get_interface_info_cb(struct nl_msg *msg, void *arg)
{
    char exec_str[512] = {0};
    // start to parse msg
    struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
    const char *indent = "";
    int *done = (int *)arg;
    int channel = 0;
    uint32_t freq = 0;

    nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
              genlmsg_attrlen(gnlh, 0), NULL);

    if (tb_msg[NL80211_ATTR_IFNAME])
        printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
    else
        printf("%sUnnamed/non-netdev interface\n", indent);

    if (tb_msg[NL80211_ATTR_WIPHY_FREQ])
    {
        freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
        channel = ieee80211_frequency_to_channel(freq);
        printf("%s\tchannel %d (%d MHz)", indent, channel, freq);

        if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH])
        {
            printf(", width: %s",
                   channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])));
            if (tb_msg[NL80211_ATTR_CENTER_FREQ1])
                printf(", center1: %d MHz",
                       nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]));
            if (tb_msg[NL80211_ATTR_CENTER_FREQ2])
                printf(", center2: %d MHz",
                       nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]));
        }
        else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
        {
            enum nl80211_channel_type channel_type;

            channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
            printf(" %s", channel_type_name(channel_type));
        }

        printf("\n");
    }
    *done = 1;
    if (!handler_script_set)
    {
        return 0;
    }
    snprintf(exec_str, sizeof(exec_str), "%s %s %s phy%d %d %d \"%s\" &", handler_script, "connected",
        nla_get_string(tb_msg[NL80211_ATTR_IFNAME]), nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]),
        channel, freq, channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])));
    system(exec_str);
    return 0;
}

int get_interface_info(struct nl80211_state *state, int devidx)
{
    printf("get_interface_info start\n");
    struct nl_msg *msg_r = nlmsg_alloc();
    int ret = 0;
    int err;
    if (!msg_r)
    {
        return -1;
    }
    struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);

    if (!cb)
    {
        fprintf(stderr, "failed to allocate netlink callbacks\n");
        return -ENOMEM;
    }

    printf("get_interface_info start1\n");
    genlmsg_put(msg_r, 0, 0, state->nl80211_id,
                0, 0, NL80211_CMD_GET_INTERFACE, 0);
    nla_put_u32(msg_r, NL80211_ATTR_IFINDEX, devidx);
    ret = nl_send_auto_complete(state->nl_sock, msg_r);
    if (ret < 0)
    {
        printf("get_interface_info start2 %d\n", ret);
        goto err;
    }
    int done = 0;
    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
              get_interface_info_cb, &done);
    // register_handler(get_interface_info_cb, NULL);
    while (err > 0)
    {
        nl_recvmsgs(state->nl_sock, cb);
        if (done == 1)
        {
            break;
        }
    }

err:
    nl_cb_put(cb);
    nlmsg_free(msg_r);

    return ret;
}

int main(int argc, char **argv)
{
    int err = 0;
    if (argc == 2)
    {
        memcpy(handler_script, argv[1], 256);
        handler_script_set = 1;
        printf("Handle script is [%s]\n", handler_script);
    }
    else
    {
        // printf("Arg err.Please enter '%s xxx_handle.sh'\n", argv[0]);
        // return 1;
    }

    err = nl80211_init(&nlstate);
    if (err)
    {
        printf("nl80211_init failed\n");
        return 1;
    }

    err = __prepare_listen_events(&nlstate);
    if (err)
    {
        printf("__prepare_listen_events failed\n");
        return err;
    }

    err = __do_listen_events(&nlstate);
    if (err)
    {
        printf("__do_listen_events failed\n");
        return err;
    }

    nl80211_cleanup(&nlstate);
    return err;
}
